import datetime
import subprocess
import threading
from PIL import Image
import gradio as gr
import openai_api_request
from quantitative import BackTraderUtils
from quantitative2 import BackTraderUtils2
import akshare as ak
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt




command = ["python", "openai_api_server.py"]
process = subprocess.Popen(
    command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
    
    
    
    


def read_process_output(process):
    """Reads the process output and prints it."""
    while True:
        output = process.stdout.readline()
        if output == '' and process.poll() is not None:
            break
        if output:
            print("API Server: "+output.strip())
# 启动一个线程读取 subprocess 输出
thread = threading.Thread(target=read_process_output, args=(process,))
thread.start()
system_prompt = {
    "role": "system",
    "content":
    "你是一个专业的量化投资的助手。"
}

# 样式
css = """
/* Tabs 样式 */  
.gr-Tabs-tab {    
    font-size: 48px; /* 增加Tab标签的字体大小 */    
    padding: 10px 20px; /* 增加Tab标签的内边距 */    
    border-radius: 5px 5px 0 0; /* 可选：给Tab顶部添加圆角 */    
    cursor: pointer; /* 可选：增加鼠标悬停时的反馈 */  
}    
    
.gr-Tabs-tab.active {    
    background-color: #007BFF; /* 激活状态的Tab背景色 */    
    color: white; /* 激活状态的Tab文字颜色 */    
}    
  
/* Label 样式 */  
.gr-Label {    
    font-size: 20px; /* 增加Label的字体大小 */    
    /* 可以添加其他Label样式 */  
}    
  
/* 全局样式 */  
body {  
    overflow: hidden;  
    margin: 0; /* 移除默认的body边距 */  
    padding: 0; /* 移除默认的body内边距 */  
}  
  
/* Gradio 应用样式 */  
gradio-app {  
    width: 100vw !important;  
    height: 100vh !important;  
    padding: 3px;  
    position: absolute;  
    top: 0; /* 确保应用顶部对齐 */  
    left: 0; /* 确保应用左侧对齐 */  
    background: #ffe !important; /* 注意：这种颜色可能非常亮，确认是否符合视觉需求 */  
}  
  
/* 特定元素样式 */  
div.prose {  
    height: 600px;  
    overflow-y: scroll;  
    border: 1px solid #ccc;  
    padding: 10px;  
    background-color: white;  
    border-radius: 10px;  
    margin: 20px; /* 可选：增加外边距以增强视觉效果 */  
}  
  
/* 滚动条样式 */  
div.prose::-webkit-scrollbar {  
    width: 8px; /* 调整滚动条宽度 */  
    height: auto;  
}  
  
div.prose::-webkit-scrollbar-track {    
    background: #f1f1f1;  
    border-radius: 2px;  
}    
  
div.prose::-webkit-scrollbar-thumb {    
    background: #888;  
    border-radius: 2px;  
}  
  
div.prose::-webkit-scrollbar-thumb:hover {    
    background: #555;    
}  
  
/* 隐藏浮动元素 */  
.float {  
    display: none;  
}  
  
/* 自定义的block样式 */  
.block.svelte-12cmxck:not(.padded) {  
    background-color: transparent;  
    border: 0 !important;  
    box-shadow: none;  
    /* 如果这是影响整个布局的样式，请确保它不会与其他样式冲突 */  
}  
  
/* 图片样式 */  
.backtrade-img {  
    width: 100%;  
    height: auto;  
    display: block; /* 避免图片下方有空隙 */  
    margin: 0 auto; /* 可选：使图片在容器中水平居中 */  
}
"""

js = """
function () {
    let screenWidth = screen.availWidth; // 获取屏幕宽度
    let screenHeight = screen.availHeight; // 获取屏幕高度
    let speed = 100; // 雪花下落的速度

    function Snow(size, downSize) {
        this.box = document.querySelector('gradio-app'); // 获取容器元素
        this.size = size; // 雪花数量
        this.downSize = downSize || 10; // 每次落下的雪花数量，默认为10个
        this.item = []; // 雪花元素数组
        this.init(); // 初始化
        this.start(); // 开始下雪
    }

    // 获取相关随机数据的方法
    Snow.prototype.getRandomThings = function (type) {
        let res;
        if (type == 'left') { // 初始的left
            res = Math.round(Math.random() * (screenWidth - 30 - 10)) + 10; // 随机生成left值
            Math.random() > 0.8 ? (res = -res) : null; // 80%的概率使左边的雪花出现在左侧（left为负值）
        } else if (type == 'top') { // 初始的top
            res = -(Math.round(Math.random() * (50 - 40)) + 40); // 随机生成top值，负值使雪花在屏幕上方
        } else if (type == 'incre') { // 向下的速度
            res = Math.random() * (4 - 1) + 1; // 随机生成向下的速度
        } else if (type == 'increLeft') { // 向右的速度
            res = Math.random() * (0.8 - 0.5) + 0.5; // 随机生成向右的速度
        } else { // 雪花的大小
            res = Math.round(Math.random() * (30 - 10)) + 10; // 随机生成雪花的大小
        }
        return res;
    }

    Snow.prototype.init = function () {
        this.box.style.width = screenWidth + 'px'; // 设置容器宽度为屏幕宽度
        this.box.style.height = screenHeight + 'px'; // 设置容器高度为屏幕高度
        let fragment = document.createDocumentFragment(); // 创建文档片段，用于性能优化
        for (let i = 0; i < this.size; i++) { // 创建雪花元素
            let left = this.getRandomThings('left'); // 获取随机的left值
            let top = this.getRandomThings('top'); // 获取随机的top值
            let snowSize = this.getRandomThings('size'); // 获取随机的雪花大小
            let snow = document.createElement("div"); // 创建雪花元素
            snow.style.cssText = 'position:absolute;color:#FFFFFF;'; // 设置元素样式
            snow.style['font-size'] = snowSize + 'px'; // 设置字体大小
            snow.style.left = left + 'px'; // 设置left值
            snow.style.top = top + 'px'; // 设置top值
            //snow.innerHTML = '&#10052'; // 设置雪花图标（Unicode编码）
            snow.innerHTML = '💸'; // 设置雪花图标（Unicode编码）
            this.item.push(snow); // 添加到雪花元素数组中
            fragment.appendChild(snow); // 添加到文档片段中
        }
        this.box.appendChild(fragment); // 将文档片段添加到容器中
    }

    Snow.prototype.start = function () {
        let that = this;
        let num = 0;
        for (let i = 0; i < this.size; i++) { // 遍历雪花元素数组
            let snow = this.item[i];
            if ((i + 1) % this.downSize == 0) { // 每downSize个雪花一组，控制下落速度
                num++;
            }
            (function (s, n) { // 使用闭包保存snow和num的值
                setTimeout(function () { // 定时器，实现雪花分批下落
                    that.doStart(s); // 调用doStart方法使雪花开始下落
                }, 1000 * n) // 每隔n秒下落一组雪花
            })(snow, num)
        }
    }

    // 针对每个雪花的定时处理
    Snow.prototype.doStart = function (snow) {
        let that = this;
        (function (s) {
            let increTop = that.getRandomThings('incre'); // 获取向下的速度
            let increLeft = that.getRandomThings('increLeft'); // 获取向右的速度
            let x = parseInt(getStyle(s, 'left')), y = parseInt(getStyle(s, 'top')); // 获取当前的left和top值

            if (s.timmer) return; // 如果定时器已存在，则不执行后续代码
            s.timmer = setInterval(function () { // 设置定时器，使雪花动起来
                // 超过右边或者底部重新开始
                if (y > (screenHeight - 5) || x > (screenWidth - 30)) {
                    // 重新回到天上开始往下
                    increTop = that.getRandomThings('incre');
                    increLeft = that.getRandomThings('increLeft');

                    // 重新随机属性
                    let left = that.getRandomThings('left');
                    let top = that.getRandomThings('top');
                    let snowSize = that.getRandomThings('size');
                    s.style.left = left + 'px';
                    s.style.top = top + 'px';
                    s.style['font-size'] = snowSize + 'px';
                    y = top;
                    x = left;
                    n = 0;

                    return;
                }

                // 加上系数，当随机数大于0.5时速度加快，小于0.5时速度减慢，形成飘动效果
                x += Math.random() > 0.5 ? increLeft * 1.1 : increLeft * 0.9;
                y += Math.random() > 0.5 ? increTop * 1.1 : increTop * 0.9;

                // 设置left和top值使雪花动起来
                s.style.left = x + 'px';
                s.style.top = y + 'px';
            }, speed); // 每隔speed毫秒执行一次定时器中的代码
        })(snow)
    }

    // 获取元素的样式值
    function getStyle(obj, prop) {
        let prevComputedStyle = document.defaultView ? document.defaultView.getComputedStyle(obj, null) : obj.currentStyle;
        return prevComputedStyle[prop];
    }

    new Snow(30, 1); // 创建一个Snow对象，传入雪花数量和每批下落的雪花数量
}
"""

def plot_report_line1(fund_code, df1, df2, df3, x):
    # 设置 seaborn 风格和调色板
    sns.set(style='whitegrid')  # 设置为白色网格背景风格
    sns.set_palette("pastel")  # 使用柔和的颜色

    # 设置 Matplotlib 的字体
    plt.rcParams['font.sans-serif'] = ['SimHei']  # Show Chinese label
    plt.rcParams['axes.unicode_minus'] = False  # These two lines need to be set manually

    plt.figure(figsize=(10, 6))  # 设置图形大小
    # 找到所有DataFrame中y值列的最大绝对值
    max_abs_y = max(df1[df1.columns[1]].abs().max(),
                    df2[df2.columns[1]].abs().max(),
                    df3[df3.columns[1]].abs().max())

    # 如果最大绝对值小于100，则设置为100（或你希望的其他值）
    max_y_limit = max_abs_y

    # 设置y轴的范围
    plt.ylim(-max_y_limit, max_y_limit)
    col1 = df1.columns[1]
    col2 = df2.columns[1]
    col3 = df3.columns[1]
    # 绘制累计收益率曲线
    sns.lineplot(x=x, y=col1, data=df1, label="net profit", linewidth=2.5)
    sns.lineplot(x=x, y=col2, data=df2, label="non-GAAP net profit", linewidth=2.5)
    sns.lineplot(x=x, y=col3, data=df3, label="total operating income", linewidth=2.5)

    # 图形美化
    plt.title(f"security {fund_code} Trends in key growth rate indicators", fontsize=20, weight='bold')  # 设置标题
    plt.xlabel("report period", fontsize=12)  # 设置x轴标签
    plt.ylabel("growth rate", fontsize=12)  # 设置y轴标签
    plt.legend(fontsize=10, loc='upper right')  # 设置图例
    plt.xticks(rotation=45)  # x轴日期旋转45度
    plt.grid(True, which='both', linestyle='--', linewidth=0.7)  # 轻微的网格线
    plt.tight_layout()  # 自动调整子图间距

    # 保存图片到指定路径
    save_path = '/home/user/app/report_key_ascending_'+fund_code+'.png'
    plt.savefig(save_path, dpi=300, bbox_inches='tight')
    return save_path

def plot_report_line2(fund_code, df1, df2,):
    # 设置金融风格：简洁、清晰的颜色与线条
    sns.set(style='white', palette='dark')  # 设置为白色背景和较暗的颜色
    plt.rcParams['font.sans-serif'] = ['SimHei']  # 显示中文标签
    plt.rcParams['axes.unicode_minus'] = False  # 正确显示负号
    plt.rcParams['lines.linewidth'] = 2  # 设置较粗的线条宽度

    fig, ax1 = plt.subplots(figsize=(10, 6))  # 设置图形大小和第一个轴（ax1，左Y轴）

    # 左侧Y轴：绘制净利润曲线
    ax1.set_xlabel('Reporting period')  # 设置x轴标签
    ax1.set_ylabel('Net Profit', color='tab:blue')  # 设置左侧Y轴标签
    ax1.tick_params(axis='y', labelcolor='tab:blue')  # 设置左侧Y轴的刻度颜色

    sns.lineplot(x=df1[df1.columns[0]], y=df1[df1.columns[1]], ax=ax1, label='Net Profit', color='tab:blue')

    # 创建第二个Y轴，共享x轴
    ax2 = ax1.twinx()
    ax2.set_ylabel('Total operating income', color='tab:red')  # 设置右侧Y轴标签
    ax2.tick_params(axis='y', labelcolor='tab:red')  # 设置右侧Y轴的刻度颜色

    # 右侧Y轴：绘制营业总收入曲线
    sns.lineplot(x=df2[df2.columns[0]], y=df2[df2.columns[1]], ax=ax2, label='Total operating income', color='tab:red')
    # 添加图例到各自的轴
    ax1.legend(loc='upper left', bbox_to_anchor=(0, 1), fontsize=10)  # 左上角图例
    ax2.legend(loc='upper right', bbox_to_anchor=(1, 1), fontsize=10)  # 右上角图例
    # 图形美化
    plt.title(f"security {fund_code} Net Profit & Total operating income", fontsize=20, weight='bold')  # 设置标题
    ax1.grid(True, which='both', linestyle='--', linewidth=0.7)  # 轻微的网格线，适用于左轴
    plt.xticks(rotation=45)  # x轴日期旋转45度
    fig.tight_layout()  # 自动调整子图间距，避免标签重叠

    # 保存图片到指定路径
    save_path = '/home/user/app/report_profit_revenue_' + fund_code + '.png'
    plt.savefig(save_path, dpi=300, bbox_inches='tight')
    return save_path

def convert_money(s):  
    if pd.isna(s):  # 检查是否为NaN  
        return 0  # 或者你可以返回0或其他适当的值  
    if not isinstance(s, str):  # 检查是否为字符串  
        raise ValueError(f"Expected string, got {type(s)}")  
      
    if '亿' in s:  
        value = float(s.rstrip('亿')) * 1e8  
    elif '万' in s:  
        value = float(s.rstrip('万')) * 1e4  
    else:  
        try:  
            value = float(s)  # 尝试直接转换为浮点数  
        except ValueError:  
            raise ValueError(f"Unable to convert '{s}' to float")  
    return value   
    
def get_ak_data(fund_code:str):
    df_stock = ak.stock_individual_info_em(symbol=fund_code)
    # 股票基本信息
    stock_info = f"""
    总市值: {df_stock[df_stock['item'] == '总市值']['value'].values[0]},流通市值: {df_stock[df_stock['item'] == '流通市值']['value'].values[0]},行业: {df_stock[df_stock['item'] == '行业']['value'].values[0]},上市时间: {df_stock[df_stock['item'] == '上市时间']['value'].values[0]},股票代码: {df_stock[df_stock['item'] == '股票代码']['value'].values[0]},股票简称: {df_stock[df_stock['item'] == '股票简称']['value'].values[0]},总股本: {df_stock[df_stock['item'] == '总股本']['value'].values[0]},流通股: {df_stock[df_stock['item'] == '流通股']['value'].values[0]}
    """
    
    stock_financial_abstract_ths_df = ak.stock_financial_abstract_ths(symbol=fund_code, indicator="按报告期")
    stock_financial_abstract_ths_df_select=stock_financial_abstract_ths_df[0:6]
    stock_financial_abstract_ths_df_select = stock_financial_abstract_ths_df_select.sort_values(by='报告期', ascending=True)
    # print(stock_financial_abstract_ths_df_select)
    # 增长率
    df1 = stock_financial_abstract_ths_df_select[["报告期","净利润同比增长率"]]
    df1['净利润同比增长率'] = df1['净利润同比增长率'].str.rstrip('%').astype(float) / 100
    df2 = stock_financial_abstract_ths_df_select[["报告期","扣非净利润同比增长率"]]
    df2['扣非净利润同比增长率'] = df2['扣非净利润同比增长率'].str.rstrip('%').astype(float) / 100
    df3 = stock_financial_abstract_ths_df_select[["报告期","营业总收入同比增长率"]]
    df3['营业总收入同比增长率'] = df3['营业总收入同比增长率'].str.rstrip('%').astype(float) / 100
    img_path1=plot_report_line1(fund_code,df1,df2,df3,"报告期")
    # 净利润和营业总收入
    df11 = stock_financial_abstract_ths_df_select[["报告期","净利润"]]
    df11['净利润'] = df11['净利润'].apply(convert_money)
    # df11['净利润'] = df11['净利润'].str.rstrip('亿').astype(float)
    df12 = stock_financial_abstract_ths_df_select[["报告期", "营业总收入"]]
    df12['营业总收入'] = df12['营业总收入'].apply(convert_money)
    # df12['营业总收入'] = df12['营业总收入'].str.rstrip('亿').astype(float)
    img_path2=plot_report_line2(fund_code,df11,df12)

    # 个股分析
    stock_financial_abstract_df = ak.stock_financial_abstract(symbol="600004")
    stock_financial_abstract_df_select=stock_financial_abstract_df[['选项','指标','20240630']]
    df=stock_financial_abstract_df_select
    # 常用指标分析
    common_index_analysis = f"""
    归母净利润: {df[df['指标'] == '归母净利润']['20240630'].values[0]},营业总收入: {df[df['指标'] == '营业总收入']['20240630'].values[0]},营业成本: {df[df['指标'] == '营业成本']['20240630'].values[0]},净利润: {df[df['指标'] == '净利润']['20240630'].values[0]},扣非净利润: {df[df['指标'] == '扣非净利润']['20240630'].values[0]},股东权益合计(净资产): {df[df['指标'] == '股东权益合计(净资产)']['20240630'].values[0]},商誉: {df[df['指标'] == '商誉']['20240630'].values[0]},经营现金流量净额: {df[df['指标'] == '经营现金流量净额']['20240630'].values[0]},基本每股收益: {df[df['指标'] == '基本每股收益']['20240630'].values[0]},每股净资产: {df[df['指标'] == '每股净资产']['20240630'].values[0]},每股现金流: {df[df['指标'] == '每股现金流']['20240630'].values[0]},净资产收益率(ROE): {df[df['指标'] == '净资产收益率(ROE)']['20240630'].values[0]},总资产报酬率(ROA): {df[df['指标'] == '总资产报酬率(ROA)']['20240630'].values[0]},毛利率: {df[df['指标'] == '毛利率']['20240630'].values[0]},销售净利率: {df[df['指标'] == '销售净利率']['20240630'].values[0]},期间费用率: {df[df['指标'] == '期间费用率']['20240630'].values[0]},资产负债率: {df[df['指标'] == '资产负债率']['20240630'].values[0]}
    """

    # 每股指标分析
    per_share_index_analysis = f"""
    基本每股收益: {df[df['指标'] == '基本每股收益']['20240630'].values[0]},稀释每股收益: {df[df['指标'] == '稀释每股收益']['20240630'].values[0]},摊薄每股净资产_期末股数: {df[df['指标'] == '摊薄每股净资产_期末股数']['20240630'].values[0]},调整每股净资产_期末股数: {df[df['指标'] == '调整每股净资产_期末股数']['20240630'].values[0]},每股净资产_最新股数: {df[df['指标'] == '每股净资产_最新股数']['20240630'].values[0]},每股经营现金流: {df[df['指标'] == '每股经营现金流']['20240630'].values[0]},每股现金流量净额: {df[df['指标'] == '每股现金流量净额']['20240630'].values[0]},每股企业自由现金流量: {df[df['指标'] == '每股企业自由现金流量']['20240630'].values[0]},每股股东自由现金流量: {df[df['指标'] == '每股股东自由现金流量']['20240630'].values[0]},每股未分配利润: {df[df['指标'] == '每股未分配利润']['20240630'].values[0]},每股资本公积金: {df[df['指标'] == '每股资本公积金']['20240630'].values[0]},每股盈余公积金: {df[df['指标'] == '每股盈余公积金']['20240630'].values[0]},每股留存收益: {df[df['指标'] == '每股留存收益']['20240630'].values[0]},每股营业收入: {df[df['指标'] == '每股营业收入']['20240630'].values[0]},每股营业总收入: {df[df['指标'] == '每股营业总收入']['20240630'].values[0]},每股息税前利润: {df[df['指标'] == '每股息税前利润']['20240630'].values[0]}
    """
    

    # 盈利能力分析
    profitability_analysis = f"""
    净资产收益率(ROE): {df[df['指标'] == '净资产收益率(ROE)']['20240630'].values[0]},摊薄净资产收益率: {df[df['指标'] == '摊薄净资产收益率']['20240630'].values[0]},净资产收益率_平均: {df[df['指标'] == '净资产收益率_平均']['20240630'].values[0]},净资产收益率_平均_扣除非经常损益: {df[df['指标'] == '净资产收益率_平均_扣除非经常损益']['20240630'].values[0]},摊薄净资产收益率_扣除非经常损益: {df[df['指标'] == '摊薄净资产收益率_扣除非经常损益']['20240630'].values[0]},息税前利润率: {df[df['指标'] == '息税前利润率']['20240630'].values[0]},总资产报酬率: {df[df['指标'] == '总资产报酬率']['20240630'].values[0]},总资本回报率: {df[df['指标'] == '总资本回报率']['20240630'].values[0]},投入资本回报率: {df[df['指标'] == '投入资本回报率']['20240630'].values[0]},息前税后总资产报酬率_平均: {df[df['指标'] == '息前税后总资产报酬率_平均']['20240630'].values[0]},毛利率: {df[df['指标'] == '毛利率']['20240630'].values[0]},销售净利率: {df[df['指标'] == '销售净利率']['20240630'].values[0]},成本费用利润率: {df[df['指标'] == '成本费用利润率']['20240630'].values[0]},营业利润率: {df[df['指标'] == '营业利润率']['20240630'].values[0]},总资产净利率_平均: {df[df['指标'] == '总资产净利率_平均']['20240630'].values[0]},总资产净利率_平均(含少数股东损益): {df[df['指标'] == '总资产净利率_平均(含少数股东损益)']['20240630'].values[0]}
    """
     
    # 成长能力分析
    growth_ability_analysis = f"""
    归母净利润: {df[df['指标'] == '归母净利润']['20240630'].values[0]},营业总收入: {df[df['指标'] == '营业总收入']['20240630'].values[0]},净利润: {df[df['指标'] == '净利润']['20240630'].values[0]},扣非净利润: {df[df['指标'] == '扣非净利润']['20240630'].values[0]},营业总收入增长率: {df[df['指标'] == '营业总收入增长率']['20240630'].values[0]},归属母公司净利润增长率: {df[df['指标'] == '归属母公司净利润增长率']['20240630'].values[0]}
    """

    # 收益质量分析
    earnings_quality_analysis = f"""
    经营活动净现金/销售收入: {df[df['指标'] == '经营活动净现金/销售收入']['20240630'].values[0]},经营性现金净流量/营业总收入: {df[df['指标'] == '经营性现金净流量/营业总收入']['20240630'].values[0]},成本费用率: {df[df['指标'] == '成本费用率']['20240630'].values[0]},期间费用率: {df[df['指标'] == '期间费用率']['20240630'].values[0]},销售成本率: {df[df['指标'] == '销售成本率']['20240630'].values[0]},经营活动净现金/归属母公司的净利润: {df[df['指标'] == '经营活动净现金/归属母公司的净利润']['20240630'].values[0]},所得税/利润总额: {df[df['指标'] == '所得税/利润总额']['20240630'].values[0]}
    """

    # 财务风险分析
    financial_risk_analysis = f"""
    流动比率: {df[df['指标'] == '流动比率']['20240630'].values[0]},速动比率: {df[df['指标'] == '速动比率']['20240630'].values[0]},保守速动比率: {df[df['指标'] == '保守速动比率']['20240630'].values[0]},资产负债率: {df[df['指标'] == '资产负债率']['20240630'].values[0]},权益乘数: {df[df['指标'] == '权益乘数']['20240630'].values[0]},权益乘数(含少数股权的净资产): {df[df['指标'] == '权益乘数(含少数股权的净资产)']['20240630'].values[0]},产权比率: {df[df['指标'] == '产权比率']['20240630'].values[0]},现金比率: {df[df['指标'] == '现金比率']['20240630'].values[0]}
    """

    # 营运能力分析
    operating_capacity_analysis = f"""
    应收账款周转率: {df[df['指标'] == '应收账款周转率']['20240630'].values[0]},应收账款周转天数: {df[df['指标'] == '应收账款周转天数']['20240630'].values[0]},存货周转率: {df[df['指标'] == '存货周转率']['20240630'].values[0]},存货周转天数: {df[df['指标'] == '存货周转天数']['20240630'].values[0]},总资产周转率: {df[df['指标'] == '总资产周转率']['20240630'].values[0]},总资产周转天数: {df[df['指标'] == '总资产周转天数']['20240630'].values[0]},流动资产周转率: {df[df['指标'] == '流动资产周转率']['20240630'].values[0]},
    流动资产周转天数: {df[df['指标'] == '流动资产周转天数']['20240630'].values[0]},应付账款周转率: {df[df['指标'] == '应付账款周转率']['20240630'].values[0]}
    """
    # print(operating_capacity_analysis)
    # 用户提示词
    usr_prompt = f'''
        ```xml        
        <task_description>
        根据下述研报指标信息，撰写一篇股票研报指标的分析报告，详细解析下述股票基本信息、常用指标信息、每股指标信息、盈利能力信息、成长能力信息、收益质量信息、财务风险信息和营运能力信息的内容，包括但不限于公司基本信息介绍、常用指标和每股指标分析、盈利能力与成长能力分析、收益质量&财务风险和营运能力分析等。内容为空或者none的字段不做分析，参考example作为范例。
        </task_description>
        
        股票基本信息：{stock_info}
        常用指标信息：{common_index_analysis}
        每股指标信息：{per_share_index_analysis}
        盈利能力信息：{profitability_analysis}
        成长能力信息：{growth_ability_analysis}
        收益质量信息：{earnings_quality_analysis}
        财务风险信息：{financial_risk_analysis}
        营运能力信息：{operating_capacity_analysis}
        
        <instructions>
        1. 根据股票基本信息，生成一段话介绍公司的名称、主营业务、市值、流通股和公司特点等，要求语言简洁，通俗易懂，不超过100字。
        2. 对股票的常用指标和每股指标进行深入分析，概括总结出公司的业务进展情况、现金流、股东情况、财务情况、投资价值等，重点强调下其优势指标和劣势指标，要求语言简洁，通俗易懂，不超过300字。
        3. 对股票的盈利能力与成长能力指标进行深入分析，概括总结出公司的投资回报情况、盈利转化情况、收入增长能力和盈利稳定性，重点强调下其优势指标和劣势指标，要求语言简洁，通俗易懂，不超过200字。
        4. 对股票的收益质量、财务风险和营运能力指标进行深入分析，概括总结出公司收益质量、财务风险和营运能力的特点，要求语言简洁，通俗易懂，不超过200字。
        </instructions>
        
        <example>
        股票简介：
        中国平安（股票代码：601318），成立于2007年，主营保险业务，总市值近79万亿（注：实际市值随市场波动），流通市值超47万亿，总股本逾18亿股，流通股超11亿股，彰显其雄厚的资本实力与市场流动性。作为行业领军者，中国平安凭借多元化业务布局与科技创新，持续巩固并扩大其市场领先地位。
        常用指标与每股指标分析：
        该公司归母净利润为4.38亿元，净利润率为13.5%，显示出较强的盈利能力。营业总收入约为34.6亿元，毛利率达27.56%，表明其核心业务具有良好的盈利空间。经营现金流量净额为19.7亿元，反映出公司现金流健康，支撑未来的运营和投资需求。净资产收益率（ROE）为2.46%，说明公司对股东权益的利用效率相对较低，可能存在提升空间。资产负债率为32.91%，处于合理区间，表明公司财务结构稳健，负债风险可控。整体来看，公司具备一定的盈利能力和财务稳健性，但提升股东回报是未来的重点。 该公司基本每股收益和稀释每股收益均为0.18元，显示出公司盈利能力的稳定性。每股净资产约为7.54元，反映出公司资产质量较高。每股经营现金流为0.83元，说明公司有较强的现金流动性，保障了日常运营和发展需求。每股未分配利润为1.96元，显示公司有充足的利润储备用于未来分红或再投资。每股资本公积金为4.16元，表明公司在资本积累上有良好的基础。整体来看，公司具备较为稳健的财务状况和持续盈利能力。
        盈利能力与成长能力分析：
        该公司净资产收益率（ROE）为2.46%，表明股东权益的回报较低，且扣除非经常损益后的ROE为2.38%，显示主营业务的盈利能力有限。毛利率为27.56%，反映公司在成本控制方面有一定优势，但销售净利率为13.5%，表明盈利的转换效率不高。息税前利润率为20.12%，说明公司在运营利润率上有一定优势。总资产报酬率为2.62%，显示公司资产的利用效率一般。整体来看，公司盈利能力稳定，但提升资产回报率和股东回报仍是未来的主要挑战。该公司营业总收入增长率为19.72%，显示出较强的收入增长能力，归母净利润增长率高达177.04%，表明公司盈利能力大幅提升，尤其是在扣除非经常损益后的净利润表现也较为稳健。整体来看，公司具备较强的成长潜力，收入与利润增长表现突出。
        
        收益质量、财务风险和营运能力分析：
        该公司经营活动净现金与营业收入的比率为56.92%，显示出较强的现金回收能力，且净现金流远超归母净利润，表明收益质量较高。成本费用率为80.41%，销售成本控制较好，期间费用率为7.97%，显示出较为稳健的成本管理能力。整体收益质量良好。该公司流动比率为0.85，速动比率为0.83，均低于1，表明短期偿债能力较弱。资产负债率为32.91%，处于合理水平，财务结构较为稳健。现金比率为0.61，显示一定的现金流缓冲能力，整体财务风险可控，但短期流动性压力值得关注。该公司应收账款周转天数为56.61天，显示出较快的回款能力，存货周转天数仅为5.78天，表明存货管理效率高。然而，总资产周转率为0.13，资产利用效率较低，流动资产周转天数为246.34天，反映出流动资产周转较慢，整体营运能力存在提升空间。
        </example>
        ```
    '''
    messages = [system_prompt]
    messages.append({"role": "user", "content": str(usr_prompt)})
    res = openai_api_request.simple_chat(messages=messages, use_stream=True)
    complete_message=''
    for chunk in res:
        delta_content = chunk.choices[0].delta.content
        complete_message += delta_content
        yield complete_message, None, None  # 每次yield只更新Markdown内容，图片设为None
    image1 = Image.open(img_path1)
    image2 = Image.open(img_path2)
    # 最后一次返回图片
    yield complete_message, image1, image2  # 返回最终完整的Markdown和图片


# 这是一个模拟的后台线程，用于从 SSE 接收数据
def fetch_backtrade_data(
        stock_code: str,
        hq_begin_date: datetime,
        hq_end_date: datetime,
        strategy: str
):
    if not stock_code:
        raise ValueError("请输入股票代码！")
    if not hq_begin_date:
        raise ValueError("请选择行情开始日期！")
    if not hq_end_date:
        raise ValueError("请选择行情结束日期！")
    if not strategy:
        raise ValueError("请选择策略！")
    save_fig_path=r"/home/user/app/lianghuahuicexiaozhushou_"+stock_code+".png"
    # 回测结果
    backtrade_ret = BackTraderUtils.back_test(ticker_symbol=stock_code, start_date=hq_begin_date, end_date=hq_end_date, strategy=strategy, save_fig=save_fig_path)

    # 用户提示词
    usr_prompt = f'''
        ```xml
        <task_description>
        撰写一篇策略回测分析报告，详细解析下述backtrade回测策略返回的内容，包括但不限于策略回测情况的整体总结、回报总结、风险总结、交易过程分析等。内容为空或者none的字段不做分析，金额单位是元，参考example作为范例。
        </task_description>
        
        回测策略名称：{strategy}
        策略回测结果：{backtrade_ret}
        
        <instructions>
        1. 根据回测策略名称，简单一小段话介绍回测的策略原理，以及优势和风险，要求语言简洁，通俗易懂。
        2. 总结策略回测地整体情况，包括但不限于Starting Portfolio Value和Final Portfolio Value的陈述与对比分析，回报率（rtot）、平均回报率（ravg）、标准化回报率（rnorm）、夏普比率Sharpe Ratio等的分析。
        3. 分析策略回测的风险情况，包括但不限于最大回撤（Drawdown）、最大回撤期间损失的资金（moneydown）等。
        4. 对交易过程进行数据上的概括总结，并对交易过程内容进行归纳分析，点出收益最亮眼的交易操作。
        </instructions>
        
        <example>
        策略简述及特点:
        SmaStrategy是一种基于移动平均线的交易策略，它通过比较短期与长期移动平均线的位置来判断买入或卖出时机。这种策略的优势在于规则简单明了，易于执行，能够跟随市场趋势。然而，它也存在滞后性风险，即在趋势反转时可能反应迟缓，导致亏损。
        回测整体表现:
        策略初始资金为1,000,000元，最终价值为992,306.97元，说明在回测期间，投资组合轻微缩水约0.77%。回报率方面，总回报率为-0.77%，平均每日回报接近于零但稍负，表明策略未能实现正向盈利。标准化回报率为-0.73%，夏普比率为-5.28，这显示出每承受一单位风险，预期获得的负回报，表明策略风险调整后表现不佳。
        风险评估:
        最大回撤达到76.93%，意味着在最不利时期，投资组合价值从峰值跌至谷底减少了7693.03元，这是个相当显著的波动，提示了策略在风险管理上存在重大挑战。
        交易过程概览:
        策略进行了两次交易，均以亏损结束，没有盈利交易。平均每笔交易亏损3846.52元，且所有交易均为做多。最长交易持续时间为12天，最短为3天，平均持仓时间为7.5天。所有交易均未实现正收益，其中最大单笔亏损达到6467.63元，凸显了策略在实际操作中的困难。
        </example>
        ```
    '''
    messages = [system_prompt]
    messages.append({"role": "user", "content": str(usr_prompt)})
    complete_message = ''
    res = openai_api_request.simple_chat(messages=messages, use_stream=True)
    for chunk in res:
        delta_content = chunk.choices[0].delta.content
        complete_message += delta_content
        yield complete_message, None  # 每次yield只更新Markdown内容，图片设为None
    image = Image.open(save_fig_path)
    # 最后一次返回图片
    yield complete_message, image  # 返回最终完整的Markdown和图片

# 这是一个模拟的后台线程，用于从 SSE 接收数据
def fetch_backtrade_data2(
        stock_code1: str,
        stock_code2: str,
        hq_begin_date: datetime,
        hq_end_date: datetime,
        strategy: str
):
    if not stock_code1:
        raise ValueError("请输入股票代码1！")
    if not stock_code2:
        raise ValueError("请输入股票代码2！")
    if not hq_begin_date:
        raise ValueError("请选择行情开始日期！")
    if not hq_end_date:
        raise ValueError("请选择行情结束日期！")
    if not strategy:
        raise ValueError("请选择策略！")
    save_fig_path=r"/home/user/app/lianghuahuicexiaozhushou_multi_"+stock_code1+"_"+stock_code2+".png"
    # 回测结果
    backtrade_ret = BackTraderUtils2.back_test(ticker_symbol=stock_code1,ticker_symbol2=stock_code2, start_date=hq_begin_date, end_date=hq_end_date, strategy=strategy, save_fig=save_fig_path)

    # 用户提示词
    usr_prompt = f'''
        ```xml
        <task_description>
        撰写一篇策略回测分析报告，详细解析下述backtrade回测策略返回的内容，包括但不限于策略回测情况的整体总结、回报总结、风险总结、交易过程分析等。内容为空或者none的字段不做分析，金额单位是元，参考example作为范例。
        </task_description>
        
        回测策略名称：{strategy}
        策略回测结果：{backtrade_ret}
        
        <instructions>
        1. 根据回测策略名称，简单一小段话介绍回测的策略原理，以及优势和风险，要求语言简洁，通俗易懂。
        2. 总结策略回测地整体情况，包括但不限于Starting Portfolio Value和Final Portfolio Value的陈述与对比分析，回报率（rtot）、平均回报率（ravg）、标准化回报率（rnorm）、夏普比率Sharpe Ratio等的分析。
        3. 分析策略回测的风险情况，包括但不限于最大回撤（Drawdown）、最大回撤期间损失的资金（moneydown）等。
        4. 对交易过程进行数据上的概括总结，并对交易过程内容进行归纳分析，点出收益最亮眼的交易操作。
        </instructions>
        <example>
        策略简述及特点:
        SmaStrategy是一种基于移动平均线的交易策略，它通过比较短期与长期移动平均线的位置来判断买入或卖出时机。这种策略的优势在于规则简单明了，易于执行，能够跟随市场趋势。然而，它也存在滞后性风险，即在趋势反转时可能反应迟缓，导致亏损。
        回测整体表现:
        策略初始资金为1,000,000元，最终价值为992,306.97元，说明在回测期间，投资组合轻微缩水约0.77%。回报率方面，总回报率为-0.77%，平均每日回报接近于零但稍负，表明策略未能实现正向盈利。标准化回报率为-0.73%，夏普比率为-5.28，这显示出每承受一单位风险，预期获得的负回报，表明策略风险调整后表现不佳。
        风险评估:
        最大回撤达到76.93%，意味着在最不利时期，投资组合价值从峰值跌至谷底减少了7693.03元，这是个相当显著的波动，提示了策略在风险管理上存在重大挑战。
        交易过程概览:
        策略进行了两次交易，均以亏损结束，没有盈利交易。平均每笔交易亏损3846.52元，且所有交易均为做多。最长交易持续时间为12天，最短为3天，平均持仓时间为7.5天。所有交易均未实现正收益，其中最大单笔亏损达到6467.63元，凸显了策略在实际操作中的困难。
        </example>
        ```
    '''
    messages = [system_prompt]
    messages.append({"role": "user", "content": str(usr_prompt)})
    complete_message = ''
    res = openai_api_request.simple_chat(messages=messages, use_stream=True)
    for chunk in res:
        delta_content = chunk.choices[0].delta.content
        complete_message += delta_content
        yield complete_message, None  # 每次yield只更新Markdown内容，图片设为None
    image = Image.open(save_fig_path)
    # 最后一次返回图片
    yield complete_message, image  # 返回最终完整的Markdown和图片

# Gradio UI部分
with gr.Blocks(css=css, js=js, title='量化策略与研报分析工具') as demo:
    with gr.Tabs():
        # 第一个Tab：研报分析
        with gr.Tab("个股分析"):
            title1 = gr.Label(value='个股研报透视分析')
            with gr.Row():
                with gr.Column():
                    stock_input_analysis = gr.Textbox(label="输入股票代码，如：601318", value="601318")
                with gr.Column():
                    btn_analysis = gr.Button("生成研报分析")
            with gr.Row():
                with gr.Column():
                    img1 = gr.Image(label="个股关键增长率指标走势", type='pil', elem_classes='backtrade-img')
                    img2 = gr.Image(label="个股净利润与营业总收入变化图", type='pil', elem_classes='backtrade-img')
                with gr.Column():
                    analysis_md = gr.Markdown()
            btn_analysis.click(fn=get_ak_data, inputs=[stock_input_analysis], outputs=[analysis_md,img1,img2])

        # 第二个Tab：量化回测
        with gr.Tab("个股量化回测"):
            title2 = gr.Label(value='量化回测神器')
            with gr.Row():
                with gr.Column():
                    stock_input_backtest = gr.Textbox(label="输入股票代码，如：601318.SH", value="601318.SH")
                    hq_begin_date_sel = gr.Textbox(label='行情开始日期，如：20191231', value="20191231")
                with gr.Column():
                    strategy_sel = gr.Dropdown(label='策略', choices=[
                        'TurtleStrategy:TurtleStrategy',
                        'harami:haramiStrategy',
                        'average_profit_macd:MACDStrategy',
                        'kdj:KDJStrategy',
                        'kdj_macd:KdjMacdStrategy',
                        'SmaStrategy:SmaStrategy'
                    ], value="harami:haramiStrategy")
                    hq_end_date_sel = gr.Textbox(label='行情结束日期，如：20210101', value="20210101")
                with gr.Column():
                    btn_backtest = gr.Button("开始回测")
            with gr.Row():
                with gr.Column():
                    img = gr.Image(label="个股回测图像", type='pil', elem_classes='backtrade-img')
                with gr.Column():
                    md = gr.Markdown()
            btn_backtest.click(fn=fetch_backtrade_data,
                               inputs=[stock_input_backtest, hq_begin_date_sel, hq_end_date_sel, strategy_sel],
                               outputs=[md, img])
        # 第三个Tab：投资组合量化回测
        with gr.Tab("投资组合回测"):
            title3 = gr.Label(value='投资组合量化回测')
            with gr.Row():
                with gr.Column():
                    stock_input_backtest1 = gr.Textbox(label="输入股票1代码，如：601318.SH", value="601318.SH")
                    hq_begin_date_sel = gr.Textbox(label='行情开始日期，如：20191231', value="20191231")
                with gr.Column():
                    stock_input_backtest2 = gr.Textbox(label="输入股票2代码，如：601939.SH", value="601939.SH")
                    hq_end_date_sel = gr.Textbox(label='行情结束日期，如：20210101', value="20210101")
                with gr.Column():
                    strategy_sel = gr.Dropdown(label='策略', choices=[
                        'SmaStrategy2:SmaStrategy2'
                    ], value="SmaStrategy2:SmaStrategy2")
                    btn_backtest = gr.Button("开始回测")
            with gr.Row():
                with gr.Column():
                    img4 = gr.Image(label="投资组合回测图像", type='pil', elem_classes='backtrade-img')
                with gr.Column():
                    md = gr.Markdown()
            btn_backtest.click(fn=fetch_backtrade_data2,
                               inputs=[stock_input_backtest1, stock_input_backtest2, hq_begin_date_sel, hq_end_date_sel, strategy_sel],
                               outputs=[md, img4])

demo.queue()
demo.launch(server_name='0.0.0.0')

